// @Author miaoqing
// @Date 2024/03/28 15:13:00
// @Desc
package logic

import (
	"core/component/router"
	"core/component/timer"
	"core/lockstepserver/pkg/network"
	l4g "github.com/alecthomas/log4go"
	"sync"
	"sync/atomic"
	"time"
)

const (
	Frequency   = 30                      // 每分钟心跳频率
	TickTimer   = time.Second / Frequency // 心跳Timer
	TimeoutTime = time.Minute * 5         // 超时时间
)

type packet struct {
	id  uint64
	msg network.Packet
}

// Room 战斗房间
type Room struct {
	wg sync.WaitGroup

	roomID      uint64
	players     []uint64
	typeID      int32
	closeFlag   int32
	timeStamp   int64
	secretKey   string
	logicServer string
	exitChan    chan struct{}
	msgQ        chan interface{}
	game        *Game
	router      *router.Router
	timer       *timer.Timer
}

// NewRoom 构造
func newRoom(id uint64, typeID int32, players []uint64, randomSeed int64, logicServer string) *Room {
	r := &Room{
		roomID:      id,
		players:     players,
		typeID:      typeID,
		exitChan:    make(chan struct{}),
		msgQ:        make(chan interface{}, 2048),
		router:      router.NewRouter(),
		timeStamp:   time.Now().Unix(),
		logicServer: logicServer,
		secretKey:   "test_room",
	}
	r.game = newGame(id, players, randomSeed, r)
	r.registerRoomHandler()
	r.registerTimer()
	go r.run()
	return r
}

func (r *Room) registerTimer() {
	r.timer.RegTimer(r.game.gameTicker, 1*time.Second)
}

// ID room ID
func (r *Room) ID() uint64 {
	return r.roomID
}

// SecretKey secret key
func (r *Room) SecretKey() string {
	return r.secretKey
}

// TimeStamp time stamp
func (r *Room) TimeStamp() int64 {
	return r.timeStamp
}

// IsOver 是否已经结束
func (r *Room) IsOver() bool {
	return atomic.LoadInt32(&r.closeFlag) != 0
}

// HasPlayer 是否有这个player
func (r *Room) HasPlayer(id uint64) bool {
	for _, v := range r.players {
		if v == id {
			return true
		}
	}

	return false
}

// Run 主循环
func (r *Room) run() {
	r.wg.Add(1)
	defer r.wg.Done()
	defer func() {
		err := recover()
		if nil != err {
			l4g.Error("[room(%d)] Run error:%+v", r.roomID, err)
		}
		r.game.Cleanup()
		l4g.Warn("[room(%d)] quit! total time=[%d]", r.roomID, time.Now().Unix()-r.timeStamp)
	}()

	// 心跳
	ticker := time.NewTicker(500 * time.Microsecond)
	defer ticker.Stop()

	// 超时timer
	timeoutTimer := time.NewTimer(TimeoutTime)

	l4g.Info("[room(%d)] players:%v running...", r.roomID, r.players)

LOOP:
	for {
		select {
		case <-ticker.C:
			r.timer.Loop()
		case <-r.exitChan:
			//l4g.Error("[room(%d)] force exit", r.roomID)
			return
		case <-timeoutTimer.C:
			//l4g.Error("[room(%d)] time out", r.roomID)
			break LOOP
		case msg := <-r.msgQ:
			data, ok := msg.([]byte)
			if ok {
				r.onMessage(data)
			}
		}
	}

	r.game.Close()

	for i := 3; i > 0; i-- {
		<-time.After(time.Second)
		l4g.Info("[room(%d)] quiting %d...", r.roomID, i)
	}
}

// Stop 强制关闭
func (r *Room) Stop() {
	close(r.exitChan)
	r.wg.Wait()
}

func (r *Room) onMessage(data []byte) {
	r.router.Route(data)
}
